<!DOCTYPE html>
<html>
<head>
    <title>Rutherford Scattering Diagram</title>
</head>
<body>
<canvas id="canvas" width="600" height="450" style="border:1px solid #d3d3d3;"></canvas>
<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';

    /**
     * Draws an arrow on the canvas context.
     * @param {CanvasRenderingContext2D} ctx - The canvas context.
     * @param {number} fromx - The x-coordinate of the arrow's start point.
     * @param {number} fromy - The y-coordinate of the arrow's start point.
     * @param {number} tox - The x-coordinate of the arrow's end point (tip).
     * @param {number} toy - The y-coordinate of the arrow's end point (tip).
     * @param {number} headlen - The length of the arrowhead sides.
     */
    function drawArrow(ctx, fromx, fromy, tox, toy, headlen) {
        headlen = headlen || 10;
        const dx = tox - fromx;
        const dy = toy - fromy;
        const angle = Math.atan2(dy, dx);
        ctx.moveTo(fromx, fromy);
        ctx.lineTo(tox, toy);
        ctx.moveTo(tox, toy);
        ctx.lineTo(tox - headlen * Math.cos(angle - Math.PI / 6), toy - headlen * Math.sin(angle - Math.PI / 6));
        ctx.moveTo(tox, toy);
        ctx.lineTo(tox - headlen * Math.cos(angle + Math.PI / 6), toy - headlen * Math.sin(angle + Math.PI / 6));
    }

    // --- Core Parameters ---
    const M_pos = { x: 400, y: 200 };
    const intersection_pos = { x: 180, y: 200 };
    
    // The angle theta shown in the diagram is the angle between the asymptotes on the left.
    // Based on the visual, it's an obtuse angle. Let's use 110 degrees.
    const theta_diagram_deg = 110; 
    const theta_diagram_rad = theta_diagram_deg * Math.PI / 180;
    
    // phi is the half-angle of the asymptote cone.
    const phi = theta_diagram_rad / 2;

    const angle_top_asymptote = -phi; // Angle with horizontal for the upper (incoming) asymptote
    const angle_bot_asymptote = phi;  // Angle with horizontal for the lower (outgoing) asymptote

    // --- 1. Draw Dashed Lines (Asymptotes and Axis) ---
    ctx.save();
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.setLineDash([6, 4]);

    // Horizontal axis of symmetry
    ctx.beginPath();
    ctx.moveTo(50, M_pos.y);
    ctx.lineTo(550, M_pos.y);
    ctx.stroke();

    // Asymptotes
    const asym_len_right = 400;
    const asym_len_left = 150;

    // Top asymptote
    ctx.beginPath();
    ctx.moveTo(intersection_pos.x - asym_len_left * Math.cos(angle_top_asymptote), intersection_pos.y - asym_len_left * Math.sin(angle_top_asymptote));
    ctx.lineTo(intersection_pos.x + asym_len_right * Math.cos(angle_top_asymptote), intersection_pos.y + asym_len_right * Math.sin(angle_top_asymptote));
    ctx.stroke();

    // Bottom asymptote
    ctx.beginPath();
    ctx.moveTo(intersection_pos.x - asym_len_left * Math.cos(angle_bot_asymptote), intersection_pos.y - asym_len_left * Math.sin(angle_bot_asymptote));
    ctx.lineTo(intersection_pos.x + asym_len_right * Math.cos(angle_bot_asymptote), intersection_pos.y + asym_len_right * Math.sin(angle_bot_asymptote));
    ctx.stroke();

    ctx.restore();

    // --- 2. Draw Trajectory ---
    ctx.save();
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 2.5;
    ctx.beginPath();
    // A quadratic Bezier curve provides a good approximation for a hyperbola in a diagram.
    // The control point is the intersection of the asymptotes.
    const curve_start = { x: 280, y: 115 };
    const curve_end = { x: 520, y: 360 };
    ctx.moveTo(curve_start.x, curve_start.y);
    ctx.quadraticCurveTo(intersection_pos.x, intersection_pos.y, curve_end.x, curve_end.y);
    ctx.stroke();

    // Arrow at the end of the trajectory to show final direction
    ctx.beginPath();
    const tangent_angle_end = Math.atan2(curve_end.y - intersection_pos.y, curve_end.x - intersection_pos.x);
    const arrow_start_x = curve_end.x - 20 * Math.cos(tangent_angle_end);
    const arrow_start_y = curve_end.y - 20 * Math.sin(tangent_angle_end);
    drawArrow(ctx, arrow_start_x, arrow_start_y, curve_end.x, curve_end.y, 10);
    ctx.stroke();
    
    ctx.restore();

    // --- 3. Draw Particles and Labels ---
    ctx.fillStyle = 'black';
    ctx.strokeStyle = 'black';
    ctx.font = 'italic 20px Times New Roman';

    // Particle M (fixed scatterer)
    ctx.beginPath();
    ctx.arc(M_pos.x, M_pos.y, 4, 0, 2 * Math.PI);
    ctx.fill();
    ctx.fillText('M', M_pos.x + 10, M_pos.y + 7);

    // Particle m (projectile)
    const m_pos = { x: 310, y: 130 };
    ctx.beginPath();
    ctx.arc(m_pos.x, m_pos.y, 4, 0, 2 * Math.PI);
    ctx.fill();
    ctx.fillText('m', m_pos.x, m_pos.y - 12);
    
    // Velocity vector v₀
    ctx.save();
    ctx.lineWidth = 1.5;
    ctx.beginPath();
    const v0_len = 50;
    // The vector is drawn parallel to the incoming asymptote, with its tip at particle m's initial position.
    const v0_start_x = m_pos.x - v0_len * Math.cos(angle_top_asymptote);
    const v0_start_y = m_pos.y - v0_len * Math.sin(angle_top_asymptote);
    drawArrow(ctx, v0_start_x, v0_start_y, m_pos.x, m_pos.y, 10);
    ctx.stroke();
    ctx.font = 'italic 22px Times New Roman';
    ctx.fillText('v', v0_start_x - 18, v0_start_y);
    ctx.font = 'italic 16px Times New Roman';
    ctx.fillText('0', v0_start_x - 10, v0_start_y + 5);
    ctx.restore();

    // --- 4. Draw Angle θ ---
    ctx.save();
    ctx.lineWidth = 1;
    ctx.beginPath();
    const arc_radius = 80;
    const start_angle_arc = Math.PI - phi; // Angle of top-left asymptote
    const end_angle_arc = Math.PI + phi;   // Angle of bottom-left asymptote
    ctx.arc(intersection_pos.x, intersection_pos.y, arc_radius, start_angle_arc, end_angle_arc, false); // false for Clockwise
    ctx.stroke();

    // Arrow on the arc (pointing CW)
    ctx.beginPath();
    const arrow_arc_angle = end_angle_arc;
    const arrow_head_x = intersection_pos.x + arc_radius * Math.cos(arrow_arc_angle);
    const arrow_head_y = intersection_pos.y + arc_radius * Math.sin(arrow_arc_angle);
    const arrow_tail_angle = arrow_arc_angle - 0.15; // Angle for the tail of the small arrow
    const arrow_tail_x = intersection_pos.x + arc_radius * Math.cos(arrow_tail_angle);
    const arrow_tail_y = intersection_pos.y + arc_radius * Math.sin(arrow_tail_angle);
    drawArrow(ctx, arrow_tail_x, arrow_tail_y, arrow_head_x, arrow_head_y, 8);
    ctx.stroke();
    
    // Label for theta
    ctx.font = 'italic 24px Times New Roman';
    ctx.fillText('θ', intersection_pos.x - arc_radius - 25, intersection_pos.y + 10);
    ctx.restore();


    // --- 5. Draw Impact Parameter b ---
    ctx.save();
    ctx.lineWidth = 1;
    
    // Calculate point on the top asymptote that is closest to M
    const IM_dist = M_pos.x - intersection_pos.x;
    const perp_pt_x = intersection_pos.x + IM_dist * Math.cos(phi) * Math.cos(phi);
    const perp_pt_y = intersection_pos.y - IM_dist * Math.cos(phi) * Math.sin(phi);

    // Draw line from M to the perpendicular point
    ctx.beginPath();
    ctx.moveTo(M_pos.x, M_pos.y);
    ctx.lineTo(perp_pt_x, perp_pt_y);
    ctx.stroke();

    // Draw perpendicular tick marks
    const tick_len = 5;
    const line_angle = Math.atan2(perp_pt_y - M_pos.y, perp_pt_x - M_pos.x);
    // Tick at M
    ctx.moveTo(M_pos.x - tick_len * Math.cos(line_angle + Math.PI / 2), M_pos.y - tick_len * Math.sin(line_angle + Math.PI / 2));
    ctx.lineTo(M_pos.x + tick_len * Math.cos(line_angle + Math.PI / 2), M_pos.y + tick_len * Math.sin(line_angle + Math.PI / 2));
    // Tick at perp_pt
    ctx.moveTo(perp_pt_x - tick_len * Math.cos(line_angle + Math.PI / 2), perp_pt_y - tick_len * Math.sin(line_angle + Math.PI / 2));
    ctx.lineTo(perp_pt_x + tick_len * Math.cos(line_angle + Math.PI / 2), perp_pt_y + tick_len * Math.sin(line_angle + Math.PI / 2));
    ctx.stroke();
    
    // Label for b
    const b_label_x = (M_pos.x + perp_pt_x) / 2 + 10;
    const b_label_y = (M_pos.y + perp_pt_y) / 2 - 5;
    ctx.font = 'italic 20px Times New Roman';
    ctx.fillText('b', b_label_x, b_label_y);

    ctx.restore();
    
    // --- 6. Draw Figure Label ---
    ctx.font = '20px "Songti SC", "SimSun", serif';
    ctx.fillStyle = 'black';
    ctx.fillText('图 1', canvas.width / 2 - 20, canvas.height - 15);

</script>
</body>
</html>